/*
** $身份: 嘞标签方法.c $
** 标签 方法
** 见版权在 炉啊.h 内
*
* * 本人所用声母表: a啊 b哔 c西 d迪 e鹅 f弗 g哥 
* h喝 i艾 j鸡 k颗 l嘞 m摸 n恩
* o欧 p匹 q气 r日 s丝 t嚏 
* u由 v微 w屋 x斯 y医 z只
*
* 一些英文单词缩写,我的翻译大多来自;有道词典,谷歌翻译,百度.
* 一些术语实在不好翻译,所以就原封不动.
* 
* 一些特有的表示特有库的术语是无法翻译的 *
* 否则编译器不能识别不能通过,第一版汉化就行不通.
* 
*/

#define 嘞标签方法_西
#define 炉啊_核心

#include "嘞前缀.h"


#include <string.h>

#include "炉啊.h"

#include "嘞调试.h"
#include "嘞做.h"
#include "嘞垃圾回收.h"
#include "嘞对象.h"
#include "嘞国.h"
#include "嘞串.h"
#include "嘞表.h"
#include "嘞标签方法.h"
#include "嘞虚拟机器.h"

static const char 由数据类型名[] = "用户数据";

炉啊艾_迪定义 const char *const 炉啊嚏_类型名_[炉啊_全部类型] = {
  "没有值",
  "零", "布尔", 由数据类型名, "号码",
  "串", "表", "函数", 由数据类型名, "线程",
  "上值", "原型" /* 这些最后的案例仅用于测试 */
};

void 炉啊嚏_初始 (炉啊_国 *嘞) {
  static const char *const 炉啊嚏_事件名[] = {  /* 秩序 标签方法 */
    "__索引", "__新索引",
    "__垃圾回收", "__模型", "__长度", "__等于",
    "__加", "__减", "__乘", "__余数", "__幂",
    "__除", "__符号除",
    "__位与", "__位或", "__位异或", "__左移", "__右移",
    "__负", "__位非", "__小于", "__小等",
    "__连接", "__调用", "__关闭"
  };
  int 艾;
  for (艾=0; 艾<标签方法_恩; 艾++) {
    哥(嘞)->标签方法名[艾] = 炉啊丝_新(嘞, 炉啊嚏_事件名[艾]);
    炉啊西_修复(嘞, 对象到垃圾回收欧(哥(嘞)->标签方法名[艾]));  /* 永远不回收这些名字 */
  }
}

/*
** 与宏 "快速标签方法" 一起使用的函数: 为缺席标记方法而优化
*/

const 嚏值 *炉啊嚏_取标签方法 (表 *事件, 嚏摸丝 单事件, 嚏串 *鹅名字) {
  const 嚏值 *标签方法 = 炉啊喝_取短串(事件, 鹅名字);
  炉啊_断言(单事件 <= 嚏摸_等于);
  if (没有标签方法(标签方法)) {  /* 没有标签方法? */
    事件->旗帜 |= 投_字节(1u<<单事件);  /* 缓存这个事实 */
    return NULL;
  }
  else return 标签方法;
}

const 嚏值 *炉啊嚏_从对象取标签方法 (炉啊_国 *嘞, const 嚏值 *欧, 嚏摸丝 事件) {
  表 *摸嚏;
  switch (嚏类型(欧)) {
    case 炉啊_嚏表:
      摸嚏 = 喝值(欧)->元表;
      break;
    case 炉啊_嚏用户数据:
      摸嚏 = 由值(欧)->元表;
      break;
    default:
      摸嚏 = 哥(嘞)->摸嚏[嚏类型(欧)];
  }
  return (摸嚏 ? 炉啊喝_取短串(摸嚏, 哥(嘞)->标签方法名[事件]) : &哥(嘞)->零值);
}

/*
** 返回对象类型的名称. 为表与用户数据用元表,
* 如果存在，使用他们的 '__名字' 元字段.
*/

const char *炉啊嚏_对象类型名 (炉啊_国 *嘞, const 嚏值 *欧) {
  表 *摸嚏;
  if ((嚏嚏是否表(欧) && (摸嚏 = 喝值(欧)->元表) != NULL) ||
      (嚏嚏是否满用户数据(欧) && (摸嚏 = 由值(欧)->元表) != NULL)) {
    const 嚏值 *名字 = 炉啊喝_取短串(摸嚏, 炉啊丝_新(嘞, "__名字"));
    if (嚏嚏是否串(名字))  /* '__名字' 是串吗? */
      return 取串(嚏丝值(名字));  /* 使用它作为类型名 */
  }
  return 嚏类型名(嚏类型(欧));  /* 否则使用标准类型名称 */
}

void 炉啊嚏_调用标签方法 (炉啊_国 *嘞, const 嚏值 *弗, const 嚏值 *匹1,
                  const 嚏值 *匹2, const 嚏值 *匹3) {
  丝嚏颗身份 函 = 嘞->顶部;
  设置对象到丝(嘞, 函, 弗);  /* 推函数 (假设 额外_栈) */
  设置对象到丝(嘞, 函 + 1, 匹1);  /* 第一 实参 */
  设置对象到丝(嘞, 函 + 2, 匹2);  /* 第二 实参 */
  设置对象到丝(嘞, 函 + 3, 匹3);  /* 第三 实参 */
  嘞->顶部 = 函 + 4;
  /* 只有在从炉啊代码中调用时元方法才会产出 */
  if (是否炉啊代码(嘞->西艾))
    炉啊迪_调用(嘞, 函, 0);
  else
    炉啊迪_调用不产出(嘞, 函, 0);
}

void 炉啊嚏_调用标签方法结果 (炉啊_国 *嘞, const 嚏值 *弗, const 嚏值 *匹1,
                     const 嚏值 *匹2, 丝嚏颗身份 结果) {
  ptrdiff_t 结果全 = 保存栈(嘞, 结果);
  丝嚏颗身份 函 = 嘞->顶部;
  设置对象到丝(嘞, 函, 弗);  /* 推函数 (假设 额外_栈) */
  设置对象到丝(嘞, 函 + 1, 匹1);  /* 第一 实参 */
  设置对象到丝(嘞, 函 + 2, 匹2);  /* 第二 实参 */
  嘞->顶部 += 3;
  /* 只有在从炉啊代码中调用时元方法才会产出 */
  if (是否炉啊代码(嘞->西艾))
    炉啊迪_调用(嘞, 函, 1);
  else
    炉啊迪_调用不产出(嘞, 函, 1);
  结果 = 恢复栈(嘞, 结果全);
  设置对象栈到栈(嘞, 结果, --嘞->顶部);  /* 将结果移动到它的位置 */
}

static int 调用二进制标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, const 嚏值 *匹2,
                      丝嚏颗身份 结果, 标签方法丝 事件) {
  const 嚏值 *标签方法 = 炉啊嚏_取标签方法从对象(嘞, 匹1, 事件);  /* 尝试第一遍操作 */
  if (没有标签方法(标签方法))
    标签方法 = 炉啊嚏_取标签方法从对象(嘞, 匹2, 事件);  /* 尝试第二遍操作 */
  if (没有标签方法(标签方法)) return 0;
  炉啊嚏_调用标签方法结果(嘞, 标签方法, 匹1, 匹2, 结果);
  return 1;
}

void 炉啊嚏_尝试二进制标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, const 嚏值 *匹2,
                    丝嚏颗身份 结果, 标签方法丝 事件) {
  if (!调用二进制标签方法(嘞, 匹1, 匹2, 结果, 事件)) {
    switch (事件) {
      case 标签方法_位与: case 标签方法_位或: case 标签方法_位异或:
      case 标签方法_左移: case 标签方法_右移: case 标签方法_位非: {
        if (嚏嚏是否号码(匹1) && 嚏嚏是否号码(匹2))
          炉啊哥_到整型错误(嘞, 匹1, 匹2);
        else
          炉啊哥_操作整型错误(嘞, 匹1, 匹2, "执行按位操作");
      }
      /* 调用永不返回，但要规避警告: *//* 失败通过 */
      default:
        炉啊哥_操作整型错误(嘞, 匹1, 匹2, "执行算术");
    }
  }
}

void 炉啊嚏_尝试合并标签方法 (炉啊_国 *嘞) {
  丝嚏颗身份 顶部 = 嘞->顶部;
  if (!调用二进制标签方法(嘞, 丝到微(顶部 - 2), 丝到微(顶部 - 1), 顶部 - 2, 标签方法_合并))
    炉啊哥_合并错误(嘞, 丝到微(顶部 - 2), 丝到微(顶部 - 1));
}

void 炉啊嚏_尝试二进制关联标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, const 嚏值 *匹2,
                                       int 触发, 丝嚏颗身份 结果, 标签方法丝 事件) {
  if (触发)
    炉啊嚏_尝试二进制标签方法(嘞, 匹2, 匹1, 结果, 事件);
  else
    炉啊嚏_尝试二进制标签方法(嘞, 匹1, 匹2, 结果, 事件);
}

void 炉啊嚏_尝试二进制艾标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, 炉啊_整数 艾2,
                                   int 触发, 丝嚏颗身份 结果, 标签方法丝 事件) {
  嚏值 辅;
  设置艾值(&辅, 艾2);
  炉啊嚏_尝试二进制关联标签方法(嘞, 匹1, &辅, 触发, 结果, 事件);
}

/*
** 调用秩序标签方法.
** 对于小于等于≤, 炉啊_兼容_小于_小等 保持与旧行为的兼容性:
* 如果没有 '__小等', 尝试 '__小于', 基于 左 <= 右 可疑 !(右 < 左) (假设总秩序).
*  若元方法在替换期间产出, 延续者必须知道它(否定结果 右<左);
*   位 调用信息状态_小于等于 在调用状态中保持该信息.
*/

int 炉啊嚏_调用秩序标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, const 嚏值 *匹2,
                      标签方法丝 事件) {
  if (调用二进制标签方法(嘞, 匹1, 匹2, 嘞->顶部, 事件))  /* 尝试原始事件 */
    return !嘞_是否假(丝到微(嘞->顶部));
#if defined(炉啊_兼容_小于_小等)
  else if (事件 == 标签方法_小等) {
      /* 尝试 '!(匹2 < 匹1)' 为 '(匹1 <= 匹2)' */
      嘞->西艾->调用状态 |= 调用信息状态_小于等于;  /* 标记它是为 '小等' 做的 '小于' */
      if (调用二进制标签方法(嘞, 匹2, 匹1, 嘞->顶部, 标签方法_小于)) {
        嘞->西艾->调用状态 ^= 调用信息状态_小于等于;  /* 清除标记 */
        return 嘞_是否假(丝到微(嘞->顶部));
      }
      /* 否则错误将移除此'西艾'; 无需清除标记 */
  }
#endif
  炉啊哥_秩序错误(嘞, 匹1, 匹2);  /* 无元方法找到 */
  return 0;  /* 去避免警告 */
}

int 炉啊嚏_调用秩序艾标签方法 (炉啊_国 *嘞, const 嚏值 *匹1, int 微2,
                       int 触发, int 是否浮点, 标签方法丝 事件) {
  嚏值 辅; const 嚏值 *匹2;
  if (是否浮点) {
    设置浮值(&辅, 投_号(微2));
  }
  else
    设置艾值(&辅, 微2);
  if (触发) {  /* 实参被改变? */
    匹2 = 匹1; 匹1 = &辅;  /* 纠正他们 */
  }
  else
    匹2 = &辅;
  return 炉啊嚏_调用秩序标签方法(嘞, 匹1, 匹2, 事件);
}

void 炉啊嚏_调整变参 (炉啊_国 *嘞, int 恩固形参, 调用信息 *西艾,
                         const 原型 *匹) {
  int 艾;
  int 实际 = 投_整型(嘞->顶部 - 西艾->函) - 1;  /* 实参号码 */
  int 恩额外 = 实际 - 恩固形参;  /* 额外实参号码 */
  西艾->由.小嘞.恩额外参 = 恩额外;
  检查栈垃圾回收(嘞, 匹->最大栈大小 + 1);
  /* 将函数复制到栈顶 */
  设置对象丝到丝(嘞, 嘞->顶部++, 西艾->函);
  /* 移动固定形参到栈顶 */
  for (艾 = 1; 艾 <= 恩固形参; 艾++) {
    设置对象丝到丝(嘞, 嘞->顶部++, 西艾->函 + 艾);
    设置零值(丝到微(西艾->函 + 艾));  /* 擦除原始形参 (为 垃圾回收) */
  }
  西艾->函 += 实际 + 1;
  西艾->顶部 += 实际 + 1;
  炉啊_断言(嘞->顶部 <= 西艾->顶部 && 西艾->顶部 <= 嘞->栈_最后);
}

void 炉啊嚏_取变参 (炉啊_国 *嘞, 调用信息 *西艾, 丝嚏颗身份 哪里, int 通缉) {
  int 艾;
  int 恩额外 = 西艾->由.小嘞.恩额外参;
  if (通缉 < 0) {
    通缉 = 恩额外;  /* 取所有可用额外实参 */
    检查栈匹(嘞, 恩额外, 哪里);  /* 确保栈空间 */
    嘞->顶部 = 哪里 + 恩额外;  /* 下一个指令将需要顶部 */
  }
  for (艾 = 0; 艾 < 通缉 && 艾 < 恩额外; 艾++)
    设置对象丝到丝(嘞, 哪里 + 艾, 西艾->函 - 恩额外 + 艾);
  for (; 艾 < 通缉; 艾++)   /* 用零完成请求的结果 */
    设置零值(丝到微(哪里 + 艾));
}